home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / OS / ZPatch.cpp < prev    next >
Text File  |  1997-06-18  |  7KB  |  251 lines

  1. /*
  2.  *  File:       ZPatch.cpp
  3.  *  Summary:       Classes to help with patching traps.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1996 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):    
  10.  *
  11.  *         <->     1/13/96    JDJ        Created (based on MacApp's class).
  12.  */
  13.  
  14. #include <ZPatch.h>
  15.  
  16. #include <OSUtils.h>
  17. #include <Traps.h>
  18.  
  19. #include <ZDebug.h>
  20. #include <ZExceptions.h>
  21.  
  22.  
  23. // ===================================================================================
  24. //    Internal Functions
  25. // ===================================================================================
  26.  
  27. //---------------------------------------------------------------
  28. //
  29. // GetTrapType
  30. //
  31. //---------------------------------------------------------------
  32. static SignedByte GetTrapType(ushort theTrap)
  33. {
  34.     return (theTrap & 0x0800) ? ToolTrap : OSTrap;
  35. }
  36.  
  37. #pragma mark -
  38.  
  39. // ===================================================================================
  40. //    class TTrapPatch
  41. // ===================================================================================
  42.  
  43. TrapPatchPtr TTrapPatch::msPatchList = nil;                    
  44.  
  45. //---------------------------------------------------------------
  46. //
  47. // TTrapPatch::TTrapPatch
  48. //
  49. //---------------------------------------------------------------
  50. TTrapPatch::TTrapPatch()
  51. {
  52.     mTrapNum = 0;
  53.     mOldTrapAddr = nil;
  54.     mPatchRoutine = nil;
  55.     mNextPatch = nil;
  56. }
  57.  
  58.  
  59. //---------------------------------------------------------------
  60. //
  61. // TTrapPatch::PatchTrap
  62. //
  63. //---------------------------------------------------------------
  64. void TTrapPatch::PatchTrap(ushort theTrapNum, void* theRoutine)
  65. {
  66.     ASSERT(mPatchRoutine != nil);    // Should have been set by the subclass.
  67.  
  68.     mTrapNum = theTrapNum;
  69.     mNextPatch = msPatchList;
  70.     msPatchList = this;
  71.  
  72.     mOldTrapAddr = NGetTrapAddress(theTrapNum, GetTrapType(theTrapNum));
  73.  
  74.     NSetTrapAddress((UniversalProcPtr) theRoutine, theTrapNum, GetTrapType(theTrapNum));
  75.  
  76.  
  77. //---------------------------------------------------------------
  78. //
  79. // TTrapPatch::GetPreviousPatchPtr
  80. //
  81. // GetPreviousPatchPtr: walks the patch list backwards to return 
  82. // the patch record just prior to (*thePatchPtr) in the patch list.
  83. //
  84. //---------------------------------------------------------------
  85. TrapPatchPtr TTrapPatch::GetPreviousPatchPtr() const
  86. {
  87.     TrapPatchPtr tempPatchPtr = msPatchList;
  88.  
  89.     if (tempPatchPtr == this)
  90.         return nil;
  91.         
  92.     while (tempPatchPtr != nil && tempPatchPtr->mNextPatch != this)
  93.         tempPatchPtr = tempPatchPtr->mNextPatch;
  94.         
  95.     return tempPatchPtr;
  96. }  
  97.  
  98.  
  99. //---------------------------------------------------------------
  100. //
  101. // TTrapPatch::GetNewerPatchPtr
  102. //
  103. // GetNewerPatchPtr: returns a newer patch record in the patch list 
  104. // which has the *same* trapNum as thePatch.
  105. //
  106. //---------------------------------------------------------------
  107. TrapPatchPtr TTrapPatch::GetNewerPatchPtr() const
  108. {
  109.     TrapPatchPtr newerPatch = nil;
  110.     TrapPatchPtr tempPatchPtr = msPatchList;
  111.  
  112.     while (tempPatchPtr != nil && tempPatchPtr != this) {
  113.         if (tempPatchPtr->mTrapNum == mTrapNum)
  114.             newerPatch = tempPatchPtr;
  115.         tempPatchPtr = tempPatchPtr->mNextPatch;
  116.     }
  117.     
  118.     return newerPatch;
  119.  
  120.  
  121. //---------------------------------------------------------------
  122. //
  123. // TTrapPatch::UnpatchTrap
  124. //
  125. //---------------------------------------------------------------
  126. void TTrapPatch::UnpatchTrap()
  127. {
  128.     // You can't patch nothing, so we use the old trap address to keep track of if we
  129.     // have a patch installed. 
  130.     if (mOldTrapAddr == nil)
  131.         return;
  132.     
  133.     // If this trap has a newer patch than the patch we're removing, then we have to take
  134.     // some extra special precautions. We have to muck with that patch's mOldTrapAddr to
  135.     // point to this patch record's mOldTrapAddr. We can pretty well ignore the case of
  136.     // an older patch on this same trap since the trapaddress in our patch record will
  137.     // be correct.
  138.     
  139.     // only set the trap address if there *isn't* a newer patch
  140.     TrapPatchPtr newerPatchPtr = this->GetNewerPatchPtr();
  141.     if (newerPatchPtr == nil)
  142.         NSetTrapAddress(mOldTrapAddr, mTrapNum, GetTrapType(mTrapNum));
  143.     else
  144.         // set up newerPatchPtr patch record so that it points to thePatch's mOldTrapAddr 
  145.         newerPatchPtr->mOldTrapAddr = mOldTrapAddr;
  146.     mOldTrapAddr = nil;
  147.     
  148.     if (mPatchRoutine) {
  149.         DisposeRoutineDescriptor(mPatchRoutine);
  150.         mPatchRoutine = nil;
  151.     }
  152.  
  153.     // Unlink the patch from the linked list of patches 
  154.     if (this == msPatchList)
  155.         msPatchList = mNextPatch;
  156.     else {
  157.         TrapPatchPtr aPatchPtr = this->GetPreviousPatchPtr();
  158.         if (aPatchPtr != nil)                    // Couldn't find thePatch, don't unpatch it
  159.             aPatchPtr->mNextPatch = mNextPatch;
  160.     }
  161.     mNextPatch = nil;
  162.  
  163.  
  164. //---------------------------------------------------------------
  165. //
  166. // TTrapPatch::UnpatchAll
  167. //
  168. //---------------------------------------------------------------
  169. void TTrapPatch::UnpatchAll()
  170. {
  171.     while (msPatchList != nil)
  172.     {
  173.         msPatchList->UnpatchTrap();
  174.     }
  175. }
  176.  
  177. #pragma mark -
  178.  
  179. // ===================================================================================
  180. //    class TPatchExitToShell
  181. // ===================================================================================
  182.  
  183. enum {
  184.     uppExitToShellProcInfo = kPascalStackBased
  185. };
  186.  
  187. #if    GENERATINGCFM
  188. typedef UniversalProcPtr ExitToShellUPP;
  189.  
  190. #define CallExitToShellProc(userRoutine)    ¥
  191.         CallUniversalProc((UniversalProcPtr)(userRoutine), uppExitToShellProcInfo)
  192. #define NewExitToShellProc(userRoutine)      ¥
  193.         (ExitToShellUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppExitToShellProcInfo, GetCurrentISA())
  194. #else
  195. typedef ProcPtr ExitToShellUPP;
  196.  
  197. #define CallExitToShellProc(userRoutine)    ¥
  198.         (*(userRoutine))()
  199. #define NewExitToShellProc(userRoutine)        ¥
  200.         (ExitToShellUPP)(userRoutine)
  201. #endif
  202.  
  203.  
  204. //---------------------------------------------------------------
  205. //
  206. // TPatchExitToShell::Install
  207. //
  208. //---------------------------------------------------------------
  209. void TPatchExitToShell::Install(ExitToShellType routine)
  210. {
  211.     ASSERT(mPatchRoutine == nil);
  212.  
  213.     mPatchRoutine = NewExitToShellProc(StripAddress(routine));
  214.     ThrowIfMemFail(mPatchRoutine);
  215.     
  216.     this->PatchTrap(_ExitToShell, mPatchRoutine);
  217. }
  218.  
  219.  
  220. //---------------------------------------------------------------
  221. //
  222. // TPatchExitToShell::Remove
  223. //
  224. //---------------------------------------------------------------
  225. void TPatchExitToShell::Remove()
  226. {
  227.     mRemovedTrapAddr = mOldTrapAddr;
  228.  
  229.     this->UnpatchTrap();
  230.  
  231.     ASSERT(mPatchRoutine == nil);
  232. }
  233.  
  234.  
  235. //---------------------------------------------------------------
  236. //
  237. // TPatchExitToShell::CallRemoved
  238. //
  239. //---------------------------------------------------------------
  240. void TPatchExitToShell::CallRemoved()
  241. {
  242.     if (mRemovedTrapAddr == nil)
  243.         mRemovedTrapAddr = mOldTrapAddr;
  244.  
  245.     CallExitToShellProc(mRemovedTrapAddr);
  246. }
  247.  
  248.